package com.pickgliss.loaders
{
	import com.pickgliss.events.LoaderEvent;
	import com.pickgliss.ui.core.Disposeable;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.external.ExternalInterface;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	import flash.system.ApplicationDomain;
	import flash.utils.ByteArray;
	import flash.utils.getTimer;
	
	[Event(name="complete",type="com.pickgliss.loader.LoaderEvent")]
	[Event(name="loadError",type="com.pickgliss.loader.LoaderEvent")]
	[Event(name="progress",type="com.pickgliss.loader.LoaderEvent")]
	/**
	 * 
	 * @author Herman
	 * 加载器的基类。
	 * 实现了对数据流的加载并对加载失败，连接失败等实现了处理方案
	 * 
	 * 也实现了 BYTE_LOADER 见get type():int 方法。
	 * 
	 * Loader的机制：
	 * 
	 * 继承自BaseLoader的加载器都是采用flash自带的URLLoader来实现数据流的加载。
	 * 如果需要继承自BaseLoader 必须通过重写__onDataLoadComplete方法来实现对加载完成的数据进行处理。
	 * 
	 * 
	 */	
	public class BaseLoader extends EventDispatcher implements Disposeable
	{
		
		public static const TRY_LOAD_TIMES:int = 3;
		
		public function BaseLoader(url:String,callback:Function = null,args:URLVariables = null)
		{
			_url = url;
			_callback = callback;
			_args = args;
			_loader = new URLLoader();
		}
		protected var _args:URLVariables;
		protected var _isComplete:Boolean;
		protected var _isSuccess:Boolean;
		protected var _loader:URLLoader;
		protected var _progress:Number=0;
		protected var _request:URLRequest;
		protected var _url:String;
		protected var _isLoading:Boolean;
		protected var _requestMethod:String = URLRequestMethod.GET;
		protected var _callback:Function;
		protected var _currentLoadPath:String;
		private var _currentTryTime:int = 0;
		
		public function get args():URLVariables
		{
			return _args;
		}
		
		public function get content():*
		{
			return _loader.data;
		}
		
		public function get isComplete():Boolean
		{
			return _isComplete;
		}
		
		public function get isSuccess():Boolean
		{
			return _isSuccess;
		}
		
		public function loadFromBytes(data:ByteArray):void
		{
			
		}
		
		public function loadFromWeb():void
		{
			startLoad(_url);
		}
		
		public function get progress():Number
		{
			return _progress
		}
		
		public function get type():int
		{
			return LoaderTypes.BYTE_LOADER;
		}
		
		public function get url():String
		{
			return _url;
		}
		
		public function set url(value:String):void
		{
			_url = value;
		}
		
		public function get isLoading():Boolean
		{
			return _isLoading;
		}
		
		protected function __onDataLoadComplete(event:Event):void
		{
			removeEvent();
			_loader.close();
			fireCompleteEvent();
		}
		
		protected function fireCompleteEvent():void
		{
			_progress = 1;
			dispatchEvent(new LoaderEvent(LoaderEvent.PROGRESS,this));
			_isSuccess = true;
			_isComplete = true;
			_isLoading = false;
			dispatchEvent(new LoaderEvent(LoaderEvent.COMPLETE,this));
			if(_callback != null) _callback(this);
		}
		
		protected function __onIOError(event:IOErrorEvent):void
		{
			onLoadError();
		}
		
		protected function __onProgress(event:ProgressEvent):void
		{
			_progress = event.bytesLoaded/event.bytesTotal;
			dispatchEvent(new LoaderEvent(LoaderEvent.PROGRESS,this));
		}
		
		protected function __onStatus(event:HTTPStatusEvent):void
		{
			if(event.status > 399)
			{
				onLoadError();
			}
		}
		
		private function addEvent():void
		{
			_loader.addEventListener(Event.COMPLETE,__onDataLoadComplete);
			_loader.addEventListener(ProgressEvent.PROGRESS,__onProgress);
			_loader.addEventListener(HTTPStatusEvent.HTTP_STATUS,__onStatus);
			_loader.addEventListener(IOErrorEvent.IO_ERROR,__onIOError);
		}
		
		protected function getLoadDataFormat():String
		{
			return URLLoaderDataFormat.BINARY;
		}
		
		protected function onLoadError():void
		{
			if(_currentTryTime < TRY_LOAD_TIMES)
			{
				_currentTryTime++;
				_isLoading = false;
				startLoad(_currentLoadPath);
			}else
			{
				removeEvent();
				_loader.close();
				_isComplete = true;
				_isLoading = false;
				_isSuccess = false;
				dispatchEvent(new LoaderEvent(LoaderEvent.LOAD_ERROR,this));
				dispatchEvent(new LoaderEvent(LoaderEvent.COMPLETE,this));
			}
		}
		
		protected function fireErrorEvent():void
		{
			dispatchEvent(new LoaderEvent(LoaderEvent.LOAD_ERROR,this));
		}
		
		protected function removeEvent():void
		{
			_loader.removeEventListener(Event.COMPLETE,__onDataLoadComplete);
			_loader.removeEventListener(ProgressEvent.PROGRESS,__onProgress);
			_loader.removeEventListener(HTTPStatusEvent.HTTP_STATUS,__onStatus);
			_loader.removeEventListener(IOErrorEvent.IO_ERROR,__onIOError);
		}
		
		protected function startLoad(path:String):void
		{
			if(_isLoading)return;
			addEvent();
			_currentLoadPath = path;
			_loader.dataFormat = getLoadDataFormat();
			_request = new URLRequest(path);
			_request.method = _requestMethod;
			_request.data = _args;
			_isLoading = true;
			_loader.load(_request);
		}
		
		public function dispose():void
		{
			_request = null;
			_loader = null;
			_callback = null;
		}
	}
}